1
|
|
|
/** |
2
|
|
|
* nextCloud - ocr |
3
|
|
|
* |
4
|
|
|
* This file is licensed under the Affero General Public License version 3 or |
5
|
|
|
* later. See the COPYING file. |
6
|
|
|
* |
7
|
|
|
* @author Janis Koehr <[email protected]> |
8
|
|
|
* @copyright Janis Koehr 2016 |
9
|
|
|
*/ |
10
|
|
|
(function() { |
11
|
|
|
/** |
12
|
|
|
* Constructor of the View object. |
13
|
|
|
* This will update the different parts of the html. |
14
|
|
|
* @param ocr |
15
|
|
|
* @param filehandler |
16
|
|
|
* @constructor |
17
|
|
|
*/ |
18
|
|
|
|
19
|
|
|
// Handlebarsjs template |
20
|
|
|
var TEMPLATE_OCR_DROPDOWN = '<div id="ocrDropdown" class="ocrUserInterface">'+ |
21
|
|
|
'{{#if noMatches}}'+ |
22
|
|
|
t('ocr', 'No languages for tesseract available')+ |
23
|
|
|
'{{else}}'+ |
24
|
|
|
t('ocr', 'Select')+ |
25
|
|
|
':'+ |
26
|
|
|
'<select id="ocrLanguage">'+ |
27
|
|
|
'{{#each languages}}'+ |
28
|
|
|
'<option value="{{this}}">{{this}}</option>'+ |
29
|
|
|
'{{/each}}'+ |
30
|
|
|
'</select>'+ |
31
|
|
|
'<input type="button" id="processOCR" value="'+ |
32
|
|
|
t('ocr', 'Process')+ |
33
|
|
|
'" />'+ |
34
|
|
|
'{{/if}}'+ |
35
|
|
|
'</div>'; |
36
|
|
|
|
37
|
|
|
var TEMPLATE_OCR_SELECTED_FILE_ACTION = '<span class="selectedActionsOCR hidden">'+ |
38
|
|
|
'<a id="selectedFilesOCR" href="" class="ocr">'+ |
39
|
|
|
'<span class="icon icon-external"></span>'+ |
40
|
|
|
'<span>'+t('ocr', 'OCR')+'</span>'+ |
41
|
|
|
'</a>'+ |
42
|
|
|
'</span>'; |
43
|
|
|
|
44
|
|
|
var View = function (ocr) { |
45
|
|
|
this._ocr = ocr; |
46
|
|
|
this._selectedFiles = []; |
47
|
|
|
this._row = undefined; |
48
|
|
|
}; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* Class prototype for the View. Following functions are available: |
52
|
|
|
* |
53
|
|
|
*/ |
54
|
|
|
View.prototype = { |
55
|
|
|
initialize: function () { |
56
|
|
|
this.renderSelectedActionButton(); |
57
|
|
|
this.registerFileActions(); |
58
|
|
|
this.registerEvents(); |
59
|
|
|
this.loopForStatus(); |
60
|
|
|
}, |
61
|
|
|
destroy: function () { |
62
|
|
|
var self = this; |
63
|
|
|
self.destroyDropdown(); |
64
|
|
|
self.destroySelectedActionButton(); |
65
|
|
|
OCA.Files.fileActions.clear(); |
66
|
|
|
OCA.Files.fileActions.registerDefaultActions(); |
67
|
|
|
}, |
68
|
|
|
registerFileActions: function () { |
69
|
|
|
var self = this; |
70
|
|
|
/** |
71
|
|
|
* Register FileAction for mimetype pdf |
72
|
|
|
*/ |
73
|
|
|
OCA.Files.fileActions.registerAction({ |
74
|
|
|
name: 'Ocr', |
75
|
|
|
displayName: t('ocr', 'OCR'), |
76
|
|
|
order: 100, |
77
|
|
|
mime: 'application/pdf', |
78
|
|
|
permissions: OC.PERMISSION_UPDATE, |
79
|
|
|
altText: t('ocr', 'OCR'), |
80
|
|
|
iconClass: 'icon-external', |
81
|
|
|
actionHandler: function (filename, context) { |
82
|
|
|
var path = context.dir || context.fileList.getCurrentDirectory(); |
83
|
|
|
var mimetype = context.fileActions.getCurrentMimeType(); |
84
|
|
|
var type = context.fileActions.getCurrentType(); |
85
|
|
|
self.renderFileAction(filename, path, type, mimetype); |
86
|
|
|
} |
87
|
|
|
}); |
88
|
|
|
/** |
89
|
|
|
* Register FileAction for mimetype image |
90
|
|
|
*/ |
91
|
|
|
OCA.Files.fileActions.registerAction({ |
92
|
|
|
name: 'Ocr', |
93
|
|
|
displayName: t('ocr', 'OCR'), |
94
|
|
|
order: 100, |
95
|
|
|
mime: 'image', |
96
|
|
|
permissions: OC.PERMISSION_UPDATE, |
97
|
|
|
altText: t('ocr', 'OCR'), |
98
|
|
|
iconClass: 'icon-external', |
99
|
|
|
actionHandler: function (filename, context) { |
100
|
|
|
var path = context.dir || context.fileList.getCurrentDirectory(); |
101
|
|
|
var mimetype = context.fileActions.getCurrentMimeType(); |
102
|
|
|
var type = context.fileActions.getCurrentType(); |
103
|
|
|
self.renderFileAction(filename, path, type, mimetype); |
104
|
|
|
} |
105
|
|
|
}); |
106
|
|
|
}, |
107
|
|
|
setSelectedFiles: function (selectedFiles) { |
108
|
|
|
var self = this; |
109
|
|
|
self._selectedFiles = selectedFiles; |
110
|
|
|
}, |
111
|
|
|
getSelectedFiles: function () { |
112
|
|
|
var self = this; |
113
|
|
|
return self._selectedFiles; |
114
|
|
|
}, |
115
|
|
|
destroySelectedActionButton: function () { |
116
|
|
|
// remove the Template |
117
|
|
|
$('.selectedActionsOCR').remove(); |
118
|
|
|
}, |
119
|
|
|
renderSelectedActionButton: function () { |
120
|
|
|
// append the TEMPLATE to correct position |
121
|
|
|
$(TEMPLATE_OCR_SELECTED_FILE_ACTION).appendTo($('#headerName-container')); |
122
|
|
|
}, |
123
|
|
|
destroyDropdown: function () { |
124
|
|
|
if ($('#ocrDropdown').length){ |
125
|
|
|
$('#ocrDropdown').detach(); |
126
|
|
|
} |
127
|
|
|
}, |
128
|
|
|
renderDropdown: function(){ |
129
|
|
|
var self = this; |
130
|
|
|
self.destroyDropdown(); |
131
|
|
|
/** global: Handlebars */ |
132
|
|
|
var template = Handlebars.compile(TEMPLATE_OCR_DROPDOWN); |
133
|
|
|
var noMatches = true; |
134
|
|
|
var languages = self._ocr.getLanguages(); |
135
|
|
|
if(languages.length > 0 && typeof languages !== undefined){ noMatches = false; } |
136
|
|
|
return template({languages: languages, noMatches: noMatches}); |
137
|
|
|
}, |
138
|
|
|
renderFileAction: function (file, path, type, mimetype) { |
139
|
|
|
var self = this; |
140
|
|
|
var html = self.renderDropdown(); |
141
|
|
|
$(html).appendTo($('tr').filterAttr('data-file',file).find('td.filename')); |
142
|
|
|
var files = [{name: file, path: path, type: type, mimetype: mimetype}]; |
143
|
|
|
self.setSelectedFiles(files); |
144
|
|
|
}, |
145
|
|
|
toggleSelectedActionButton: function () { |
146
|
|
|
var self = this; |
147
|
|
|
var selectedActionButton = $('.selectedActionsOCR'); |
148
|
|
|
var selFiles = OCA.Files.App.fileList.getSelectedFiles(); |
149
|
|
|
if(selFiles.length > 0 && typeof selFiles !== undefined){ |
150
|
|
|
//show if all have correct mimetype and type = file |
151
|
|
|
if(self._ocr.checkMimeTypes(selFiles)){ |
152
|
|
|
// show if not already shown |
153
|
|
|
selectedActionButton.removeClass('hidden'); |
154
|
|
|
}else{ |
155
|
|
|
selectedActionButton.addClass('hidden'); |
156
|
|
|
} |
157
|
|
|
}else{ |
158
|
|
|
// hide if not already hidden |
159
|
|
|
selectedActionButton.addClass('hidden'); |
160
|
|
|
self.setSelectedFiles([]); |
161
|
|
|
} |
162
|
|
|
}, |
163
|
|
|
togglePendingState: function (force) { |
164
|
|
|
var self = this; |
165
|
|
|
var html = ''; |
166
|
|
|
var pendingcount = self._ocr.getStatus().pending; |
167
|
|
|
if(force){ |
168
|
|
|
html = '<span class="icon icon-loading-small"></span> <span>' + t('ocr','OCR processing started.') + '</span>'; |
169
|
|
|
}else{ |
170
|
|
|
html = '<span class="icon icon-loading-small"></span> <span>' + pendingcount + ' ' + t('ocr','currently pending OCR requests.') + '</span>'; |
171
|
|
|
} |
172
|
|
|
if(pendingcount > 0 || force){ |
173
|
|
|
if (self._row !== undefined) { OC.Notification.hide(self._row); } |
174
|
|
|
self._row = OC.Notification.showHtml(html); |
175
|
|
|
}else{ |
176
|
|
|
if (self._row !== undefined){ |
177
|
|
|
OC.Notification.hide(self._row); |
178
|
|
|
self._row = undefined; |
179
|
|
|
} |
180
|
|
|
} |
181
|
|
|
}, |
182
|
|
|
updateFileList: function () { |
183
|
|
|
var self = this; |
184
|
|
|
OCA.Files.App.fileList.reload(); |
185
|
|
|
self.toggleSelectedActionButton(''); |
186
|
|
|
}, |
187
|
|
|
/** |
188
|
|
|
* Loops as long as there are pending objects |
189
|
|
|
*/ |
190
|
|
|
loopForStatus: function () { |
191
|
|
|
var self = this; |
192
|
|
|
$.when(self._ocr.checkStatus()).done(function(){ |
193
|
|
|
if(self._ocr.getStatus().failed > 0) { self.notifyError('OCR processing for one or more files failed. For details please contact your administrator.'); } |
194
|
|
|
if(self._ocr.getStatus().pending > 0){ |
195
|
|
|
if(self._ocr.getStatus().processed > 0) { self.updateFileList(); } |
196
|
|
|
self.togglePendingState(false); |
197
|
|
|
setTimeout($.proxy(self.loopForStatus,self), 4500); |
198
|
|
|
}else{ |
199
|
|
|
if(self._ocr.getStatus().processed > 0) self.updateFileList(); |
|
|
|
|
200
|
|
|
self.togglePendingState(false); |
201
|
|
|
} |
202
|
|
|
}).fail(function(message){ |
203
|
|
|
self.notifyError(message); |
204
|
|
|
setTimeout($.proxy(self.loopForStatus,self), 4500); |
205
|
|
|
}); |
206
|
|
|
}, |
207
|
|
|
notifyError: function (message) { |
208
|
|
|
/** global: OC */ |
209
|
|
|
OC.Notification.showHtml('<div>'+t('ocr', message)+'</div>', {timeout: 10, type: 'error'}); |
210
|
|
|
}, |
211
|
|
|
registerEvents: function(){ |
212
|
|
|
var self = this; |
213
|
|
|
// Close on click on other element |
214
|
|
|
$(document).click(function(event) { |
215
|
|
|
if(!$(event.target).closest('#ocrDropdown').length) { |
216
|
|
|
self.destroyDropdown(); |
217
|
|
|
self.setSelectedFiles([]); |
218
|
|
|
} |
219
|
|
|
}); |
220
|
|
|
// Register submit action |
221
|
|
|
$(document).on('click', '#processOCR', function(){ |
222
|
|
|
var selectedLanguage = $('#ocrLanguage').val(); |
223
|
|
|
$.when(self._ocr.process(self.getSelectedFiles(), selectedLanguage)).done(function(){ |
224
|
|
|
self.destroyDropdown(); |
225
|
|
|
self.setSelectedFiles([]); |
226
|
|
|
// status monitoring init |
227
|
|
|
self.togglePendingState(true); |
228
|
|
|
setTimeout($.proxy(self.loopForStatus,self), 4500); |
229
|
|
|
}).fail(function(message){ |
230
|
|
|
self.notifyError('OCR processing failed: ' + message); |
231
|
|
|
self.destroyDropdown(); |
232
|
|
|
}); |
233
|
|
|
}); |
234
|
|
|
// Register click selectedFilesAction |
235
|
|
|
$(document).on('click', '#selectedFilesOCR', function(){ |
236
|
|
|
var html = self.renderDropdown(); |
237
|
|
|
$(html).appendTo($('tr').find('th.column-name')); |
238
|
|
|
self.setSelectedFiles(OCA.Files.App.fileList.getSelectedFiles()); |
239
|
|
|
return false; |
240
|
|
|
}); |
241
|
|
|
// Register checkbox events |
242
|
|
|
/** global: _ */ |
243
|
|
|
OCA.Files.App.fileList.$fileList.on('change', 'td.filename>.selectCheckBox', _.bind(self.toggleSelectedActionButton, this)); |
244
|
|
|
OCA.Files.App.fileList.$el.find('.select-all').click(_.bind(self.toggleSelectedActionButton, this)); |
245
|
|
|
} |
246
|
|
|
}; |
247
|
|
|
/** global: OCA */ |
248
|
|
|
if (OCA.Ocr) { |
249
|
|
|
OCA.Ocr.View = View; |
250
|
|
|
} |
251
|
|
|
})(); |
Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.
Consider:
If you or someone else later decides to put another statement in, only the first statement will be executed.
In this case the statement
b = 42
will always be executed, while the logging statement will be executed conditionally.ensures that the proper code will be executed conditionally no matter how many statements are added or removed.